package model;

import main.RandomGenerator;
import main.Simulator;
import main.Util;

public class RouterRED extends Router {

	double avg = 0;
	double w_q = 0.002;
	int min_th = 5;
	int max_th = 15;
	double max_p = 1.0/50;
	int count = 0;
	double m = 0;
	double emptyTime = 0;

	/**
	 * Classe representando o roteador com a fila RED.
	 * @param simulator simulador 
	 * @param bufferCapacity capacidade máxima do buffer em número de pacotes
	 */
	public RouterRED(Simulator simulator, int bufferCapacity) {
		super(simulator, bufferCapacity);
	}

	/**
	 * Método que implementa o tratamento da chegada de um pacote com a fila RED.
	 */
	@Override
	public void packetArrived(Packet pack) {
		if (buffer.size() > 0) {
			avg = (1 - w_q)*avg + w_q*buffer.size();
		} else {
			double interval = simulator.getTime() - emptyTime;
			m = Util.convertMillisToSeconds(interval) / (8.0 * simulator.getProperties().getMSS() / simulator.getProperties().getCg());
			avg = Math.pow((1 - w_q), m) * avg;
		}
		
		double pb = max_p*(avg - min_th)/(max_th - min_th);
		double pa = pb / (1 - count*pb);
		
		if (avg < min_th) {
			if (buffer.size() < bufferCapacity) {
				count++;
				addPacket(pack);
			} else {
				count = 0;
			}
		} else if (avg > max_th) {
			count = 0;
		} else {
			if (RandomGenerator.nextDouble() <= pa) {
				count = 0;
			} else {
				if (buffer.size() < bufferCapacity) {
					count++;
					addPacket(pack);
				} else {
					count = 0;
				}
			}
		}
	}
	
	/**
	 * Método que programa o evento de chegada no receptor e marca o tempo em que a fila fica vazia.
	 */
	@Override
	public void sendPacket(Packet pack) {
		super.sendPacket(pack);
		
		if (buffer.isEmpty()) {
			emptyTime = simulator.getTime();
		}
	}
	
}
